<?php

/*
info: 分类管理
date: 2011-11-23
*/

if (!defined('WEBINROOT'))
{
	header("HTTP/1.0 404 Not Found");
	exit();
}

abstract class CategoryDataModel {
	
	protected $id = 'category';
	protected $title = '分类';
	static $includeDir = 'category';

	protected $categoryItemClass = 'CategoryItem';
	protected $cachekey = 'category';
	protected $tableName = '';

	protected $supportCheckRelation = true; //当删除的时候,是否支持关联数据判断
	protected $relationTableName = ''; //关联表
	protected $relationField = ''; //关联字段
	protected $relationErrorMessage = ''; //关联表错误提示信息

	protected $db = null;
	protected $webconfig = array();

	protected $useCache = true;
	protected $items = array();
	protected $filter = array();

	protected function retrieveData() {
		$result = array();
		$itemClass = $this->categoryItemClass;

		$query = $this->db->Query("SELECT * FROM {$this->webconfig['dbpre']}{$this->tableName} ORDER BY upid, sort, id");
		while ($tempData = $this->db->FetchArray($query)) {
			$result[$tempData['id']] = new $itemClass($tempData);
		}

		return $result;
	}

	public function getTitle() {
		return $this->title;
	}

	public function setUseCache($use) {
		$this->useCache = $use;
	}

	public function getUseCache() {
		return $this->useCache;
	}

	public function setDB(MysqlDB $db) {
		$this->db = $db;
	}

	protected function getCacheFile() {
		$cacheKey = $this->cachekey;

		return cache_GetCacheFile($cacheKey);
	}

	protected function getCachedData() {
		$strFile = $this->getCacheFile();

		if (file_exists($strFile)) {
			include $strFile;
			return $webcache[$this->id];
		}

		return false;
	}

	protected function writeCachedData($data) {
		$cacheKey = $this->cachekey;
		$key = $this->id;

		$cacheData = array($key => $data);
		cache_Write($cacheKey, cache_GetCacheVars($cacheData));
		
		return true;
	}

	protected function clearCachedData() {
		$strFile = $this->getCacheFile();
		@unlink($strFile);
	}

	protected function setCategoryItemClass($categoryItemClass) {
		if ($categoryItemClass) {
			if (!class_exists($categoryItemClass)) {
				throw new Exception("Category Item class $categoryItemClass not defined");
			}
			$this->categoryItemClass = $categoryItemClass;
		}
	}

	public function clearInternalCache() {
		$this->items = array();
	}

	protected function init($args) {
		global $db, $webconfig;

		if (isset($args['cache'])) {
			$this->setUseCache($args['cache']);
		}

		if (isset($args['db'])) {
			$this->db = $args['db'];
		} else {
			global_ConnectDB();
			$this->db = $db;
		}

		if (isset($args['webconfig'])) {
			$this->webconfig = $args['webconfig'];
		} else {
			$this->webconfig = $webconfig;
		}

		if (isset($args['categoryItemClass'])) {
			$this->setCategoryItemClass($args['categoryItemClass']);
		}
	}

	private function formatCategory($intacid)
	{
		if (!isset($this->items[$intacid])) {
			return FALSE;
		}
		$category = $this->items[$intacid];
		if ($intacid == $category->getUpID()) {
			return FALSE;
		}

		$tempUpClass = array(); //相对父分类
		$tempUpClassId = $category->getUpID();
		$tempLevel = 1;
		while (isset($this->items[$tempUpClassId]) && !in_array($tempUpClassId, $tempUpClass)) {
			$parentCategory = $this->items[$tempUpClassId];
			$parentCategory->increaseChild();

			$tempUpClass[] = $tempUpClassId;
			$tempLevel++;
			$tempUpClassId = $parentCategory->getUpID();
		}

		$tempUpClass[] = 0;
		$tempUpClass = array_reverse($tempUpClass);
		$category->setUpCategoryID($tempUpClass);
		$category->setDir(implode("/", $tempUpClass));
		$category->setLayer($tempLevel);

		$this->items[$intacid] = $category;
		return TRUE;
	}

	private function sortCategory($categoryA, $categoryB) {
		if ($categoryA->getDir() == $categoryB->getDir()) {
			if ($categoryA->getSort() == $categoryB->getSort()) {
				return $categoryA->getID() < $categoryB->getID() ? -1 : 1;
			}
			return $categoryA->getSort() < $categoryB->getSort() ? -1 : 1;
		} else {
			$count = min($categoryA->getLayer(), $categoryB->getLayer());
			$tempDirArrayA = explode("/", $categoryA->getDir());
			$tempDirArrayB = explode("/", $categoryB->getDir());
			for ($i=0; $i<$count; $i++) {
				
				if ($tempDirArrayA[$i] != $tempDirArrayB[$i]) {
					if ($this->items[$tempDirArrayA[$i]]->getSort() == $this->items[$tempDirArrayB[$i]]->getSort()) {
						return $this->items[$tempDirArrayA[$i]]->getID() < $this->items[$tempDirArrayB[$i]]->getID() ? -1 : 1;
					}
					return $this->items[$tempDirArrayA[$i]]->getSort() < $this->items[$tempDirArrayB[$i]]->getSort() ? -1 : 1;
				}
			}
			if ($categoryA->getLayer() < $categoryB->getLayer()) {
				if ($categoryA->getID() == $tempDirArrayB[$count]) {
					return -1;
				}
				if ($categoryA->getSort() == $this->items[$tempDirArrayB[$count]]->getSort()) {
					return $categoryA->getID() < $tempDirArrayB[$count] ? -1 : 1;
				}
				return $categoryA->getSort() < $this->items[$tempDirArrayB[$count]]->getSort() ? -1 : 1;
			} else {
				if ($categoryB->getID() == $tempDirArrayA[$count]) {
					return 1;
				}
				if ($categoryB->getSort() == $this->items[$tempDirArrayA[$count]]->getSort()) {
					return $tempDirArrayA[$count] < $categoryB->getID() ? -1 : 1;
				}
				return $this->items[$tempDirArrayA[$count]]->getSort() < $categoryB->getSort() ? -1 : 1;
			}
		}
	}

	protected function formatClassToArray($categories) {
		$tempResult = array();

		foreach ($categories as $key => $category) {
			$tempResult[$key] = $category->toArray();
		}

		return $tempResult;
	}

	public function getData() {
		if ($this->items) {
			return $this->items;
		}
		
		$needCache = false;

		if ($this->useCache) {
			if ($data = $this->getCachedData()) {
				$this->items = $data;
				return $this->items;
			} else {
				$data = $this->retrieveData();
				$needCache = true;
			}
		} else {
			$data = $this->retrieveData();
		}

		//format data
		if ($data) {
			$this->items = $data;
			foreach ($data as $key => $category) {
				$tempformat = $this->formatCategory($key);
				if (!$tempformat)
				{
					return '';
				}
			}
			//sort category
			uasort($this->items, array($this, 'sortCategory'));
			$this->items = $this->formatClassToArray($this->items);

			if ($needCache) {
				$this->writeCachedData($this->items);
			}
		}
		return $this->items;
	}

	public function getItem($id = 0) {
		if ($id) {
			if ($this->useCache) {
				$items = $this->getData();
				return isset($items[$id]) ? $items[$id] : array();
			} else {
				return $this->db->GetOne("SELECT * FROM {$this->webconfig['dbpre']}{$this->tableName} WHERE id = '{$id}'");
			}
		}
		return array();
	}

	public function getChildForLayer($categoryID = 0, $layer = 0, $containSelf = true) {
		$items = $this->getData();
		if ($categoryID == 0 && $layer == 0) {
			return $items;
		}

		if ($categoryID == 0) {
			$this->filter = array(
				'id' => $categoryID,
				'layer' => 0,
				'dir' => 0,
				'parentdir' => '0',
				'parentdirext' => '0/',
			);
		} else {
			if (!isset($items[$categoryID])) {
				return array();
			}
			$this->filter = $items[$categoryID];
			$this->filter['parentdir'] = $items[$categoryID]['dir'] .'/'. $categoryID;
			$this->filter['parentdirext'] = $items[$categoryID]['dir'] .'/'. $categoryID . '/';
		}
		$this->filter['addlayer'] = $layer;
		$this->filter['lastlayer'] = $this->filter['layer'] + $layer;
		$this->filter['parentlength'] = strlen($this->filter['parentdirext']);
		$this->filter['contain_self'] = $containSelf;
		return array_filter($items, array($this,"filterCategory"));
	}

	protected function filterCategory($category) {
		if (!$this->filter) {
			return false;
		}
		if ($category['id'] == $this->filter['id'] && $this->filter['contain_self']) {
			return true;
		}
		if ($category['layer'] > $this->filter['layer']) {
			if ($this->filter['addlayer'] > 0 && $category['layer'] > $this->filter['lastlayer']) {
				return false;
			}
			if ($category['dir'] == $this->filter['parentdir'] || strncmp($category['dir'], $this->filter['parentdirext'], $this->filter['parentlength']) == 0) {
				return true;
			}
		}

		return false;
	}

	public function formatCategoryOption($categoryId, $layer = 0, $containSelf = true) {
		$tempResult = array();
		$tempChildClass = $this->getChildForLayer($categoryId, $layer, $containSelf);
		foreach ($tempChildClass as $tempkey => $tempvalue) {
			$tempComma = $tempvalue['layer'] == 1 ? '' : "├";
			$tempvalue['showName'] = str_repeat("&nbsp;&nbsp;", $tempvalue['layer']). $tempComma .$tempvalue['name'];
			$tempvalue['tdclass'] = $tempvalue['layer'] == 1 ? ' class="evenrow"' : '';
			$tempResult[$tempkey] = $tempvalue;
		}
		return $tempResult;
	}

	//将多级数组格式成json格式
	public function formatClassToJson($categoryID = 0, $layer = 0, $containSelf = true) {
		$tempCategory = $this->getChildForLayer($categoryID, $layer, $containSelf);

		$tempvalue = array();
		foreach ($tempCategory as $key => $category) {
			$findParent = false;
			$strArrayName = '';

			array_shift($category['upCategoryID']);
			if ($category['upCategoryID']) {
				foreach ($category['upCategoryID'] as $upid) {
					if (isset($tempvalue[$upid])) {
						$findParent = true;
						$strArrayName = "\$tempvalue";
					}
					if ($findParent) {
						$strArrayName .= "[$upid]['cell']";
					}
				}
				if ($findParent) {
					$strArrayName .= "[{$category['id']}]['name'] = '{$category['name']}';";
					eval($strArrayName);
				} else {
					$tempvalue[$key]['name'] = $category['name'];
				}
			} else {
				$tempvalue[$key]['name'] = $category['name'];
			}
		}

		return json_encode($tempvalue);
	}

	public function addData($data) {
		if ($insertID = $this->db->Insert($this->tableName, $data, true)) {
			$this->clearCachedData();
			return $insertID;
		} else {
			return false;
		}
	}

	public function editData($id, $data) {
		$condition = 'id = ' . $id;
		if ($tempReturn = $this->db->Update($this->tableName, $data, $condition)) {
			$this->clearCachedData();
			return true;
		}

		return false;
	}

	public function deleteData($id = 0) {
		$tempReturn = array();

		//判断是否有下级分类
		if ($tempChildData = $this->getChildForLayer($id, 0, false)) {
			return array(
				'status' => false, 
				'msg'    => '该分类下还有子分类,不能删除.'
			);
		}
		if ($this->supportCheckRelation && $this->relationTableName && $this->relationField) {
			$query = "SELECT COUNT(*) AS totalnum FROM {$this->webconfig['dbpre']}{$this->relationTableName} WHERE {$this->relationField} = '{$id}' LIMIT 0, 1";
			
			if ($result = $this->db->GetOne($query)) {
				if ($result['totalnum'] > 0) {
					return array(
						'status' => false, 
						'msg'    => $this->relationErrorMessage
					);
				}
			}
		}
		if ($tempReturn = $this->db->Delete($this->tableName, 'id='.$id)) {
			$this->clearCachedData();
			return true;
		}

		return false;
	}

	public static function factory($type, $args) {

		$categoryModel = '';
		switch ($type) {
			case 'area':
				$categoryModel = 'AreaCategoryDataModel';
				break;
			case 'company':
				$categoryModel = 'CompanyCategoryDataModel';
				break;
			case 'coupon':
				$categoryModel = 'CouponCategoryDataModel';
				break;
			case 'news':
				$categoryModel = 'NewsCategoryDataModel';
				break;
			default:
				throw new Exception("Category type not exists");
		}

		require WEBFILEPATH.'/include/' . self::$includeDir . '/' . $categoryModel . '.php';
		
		if (!class_exists($categoryModel)) {
			throw new Exception("{$categoryModel} not found");
		}

		$model = new $categoryModel();
		$model->init($args);

		return $model;
	}
}

class CategoryItem {

	protected $ID;
	protected $upid;
	protected $name;
	protected $sort;
	protected $addtime;
	protected $child = 0;
	protected $upCategoryID = array();
	protected $dir;
	protected $layer;

	public function __construct($args) {
		if (isset($args['id'])) {
			$this->setID($args['id']);
		}
		if (isset($args['upid'])) {
			$this->setUpID($args['upid']);
		}
		if (isset($args['name'])) {
			$this->setName($args['name']);
		}
		if (isset($args['sort'])) {
			$this->setSort($args['sort']);
		}
	}

	public function setID($id) {
		$this->ID = $id;
	}

	public function getID() {
		return $this->ID;
	}

	public function setUpID($id) {
		$this->upid = $id;
	}

	public function getUpID() {
		return $this->upid;
	}

	public function setName($name) {
		$this->name = $name;
	}

	public function getName() {
		return $this->name;
	}

	public function setSort($sort) {
		$this->sort = $sort;
	}

	public function getSort() {
		return $this->sort;
	}

	public function increaseChild() {
		$this->child = $this->child + 1;
	}

	public function getChild() {
		return $this->child;
	}

	public function setUpCategoryID($data) {
		$this->upCategoryID = $data;
	}

	public function getUpCategoryID() {
		return $this->upCategoryID;
	}

	public function setDir($dir) {
		$this->dir = $dir;
	}

	public function getDir() {
		return $this->dir;
	}

	public function setLayer($layer) {
		$this->layer = $layer;
	}

	public function getLayer() {
		return $this->layer;
	}

	public function toArray() {
		return array(
			'id' => $this->getID(),
			'upid' => $this->getUpID(),
			'name' => $this->getName(),
			'sort' => $this->getSort(),
			'child' => $this->getChild(),
			'upCategoryID' => $this->getUpCategoryID(),
			'dir' => $this->getDir(),
			'layer' => $this->getLayer()
		);
	}
}